package com.quectel.sdk.hikisc.monitor;

import com.fasterxml.jackson.databind.JsonNode;
import com.quectel.sdk.hikisc.AbstractHikBaseClient;
import com.quectel.sdk.hikisc.monitor.model.EncodeDeviceDetailResp;
import com.quectel.sdk.hikisc.monitor.model.SyncCameraResp;
import com.quectel.util.common.ImageUtils;
import com.quectel.util.common.JacksonUtils;
import com.quectel.util.common.MyFileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Closeable;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 在这里编写说明
 *
 * @author: rananxin
 * @email: ryan.ran@quectel.com
 * @date: 2022-10-19 11:01:00
 */
public class MonitorClient extends AbstractHikBaseClient {

    private static final String SUCCESS_CODE = "0";
    private static final Logger LOGGER = LoggerFactory.getLogger(MonitorClient.class);

    public EncodeDeviceDetailResp encodeDeviceDetail(String indexCode) {
        final String path = "/api/resource/v1/encodeDevice/single/get";

        Map<String, Object> params = new HashMap<>();
        params.put("resourceIndexCode", indexCode);

        String response = requester.post(path, params);
        System.out.println(response);
        JsonNode respJson = JacksonUtils.parse(response);
        String code = respJson.get("code").asText();
        if (!SUCCESS_CODE.equals(code)) {
            LOGGER.error("海康 获取监控点详情异常 response {}", response);
        }
        return JacksonUtils.parse(JacksonUtils.toJsonString(respJson.get("data")), EncodeDeviceDetailResp.class);
    }

    /**
     * 人脸服务图片下载
     * 涉及的api包括:
     * 人脸服务图片下载 path:/api/frs/v1/application/picture
     * <p>
     * a)通过调用图片下载接口将URL或URI转换成二进制图片流。
     * b)该接口适用于调用方的场景无法独立从URL获取图片。
     * c)接口支持传递URL或URI。人脸监控应用服务会自行判断如何获取图片，其中URI的方式要求图片必须在ASW服务上。
     * d)当传入的图片url是超脑上的图片时会返回图片base64编码，其他情况均返回重定向地址。
     * e)若接口会返回HTTP状态码302，此时调用方需要去重定向的目标URL下载图片；若接口返回HTTP状态码200，此时接口返回图片base64编码。
     *
     * @param picCode 图片资源编码
     * @return 上传后地址
     */
    public File fetchPic(String picCode) {
        // 两种获取方式 body解码base64 和 重定向后读取流
        String url = null;
        // 人脸服务图片下载
        String str = "/api/frs/v1/application/picture";
        Map<String, Object> params = new HashMap<>();
        params.put("url", picCode);

        HttpResponse httpResponse = null;
        try {
            httpResponse = requester.postBackHttpResponse(str, params);
            HttpEntity entity = httpResponse.getEntity();
            String value = httpResponse.getEntity().getContentType().getValue();

            if (StringUtils.isNotBlank(value) && value.toLowerCase().contains("json")) {

                String body = null;
                try {
                    body = EntityUtils.toString(entity, StandardCharsets.UTF_8);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                JsonNode respJson = JacksonUtils.parse(body);
                String code = respJson.get("code").asText();
                if (SUCCESS_CODE.equals(code)) {
                    String data = respJson.get("data").asText();
                    return ImageUtils.base64ImgToTempFile(data);
                }

            } else {
                try {
                    return MyFileUtils.writeFileToTempDir(entity.getContent(), UUID.randomUUID().toString() + ".jpg", true);
                } catch (Exception e) {
                    e.printStackTrace();
                }

            }

        } finally {
            if (httpResponse != null) {
                try {
                    ((Closeable) httpResponse).close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    /**
     * 事件订阅
     * 涉及的api包括:
     * 按事件类型订阅事件 path:/api/eventService/v1/eventSubscriptionByEventTypes
     *
     * @param eventCode 事件编码集合
     * @param url       回调地址
     */
    public boolean eventSub(Integer[] eventCode, String url) {
        Map<String, Object> params = new HashMap<>();
        params.put("eventTypes", eventCode);
        params.put("eventDest", url);
        params.put("subType", 2);

        final String path = "/api/eventService/v1/eventSubscriptionByEventTypes";

        String response = requester.post(path, params);
        JsonNode respJson = JacksonUtils.parse(response);
        String code = respJson.get("code").asText();
        return SUCCESS_CODE.equals(code);
    }

    /**
     * 获取监控点资源列表
     * 涉及的api包括：
     * 分页获取监控点资源 path:/api/resource/v1/cameras
     *
     * @return 全部监控点资源集合
     */
    public List<SyncCameraResp> drawResources() {
        final int fetchSize = 999;
        Map<String, Object> params = new HashMap<>();
        params.put("pageNo", 1);
        params.put("pageSize", fetchSize);

        final String path = "/api/resource/v1/cameras";

        List<SyncCameraResp> result = new ArrayList<>();
        while (true) {
            String response = requester.post(path, params);
            JsonNode respJson = JacksonUtils.parse(response);
            String code = respJson.get("code").asText();
            if (!SUCCESS_CODE.equals(code)) {
                LOGGER.error("海康 获取监控点资源异常 response {}", response);
                break;
            }
            JsonNode value = respJson.findValue("data").findValue("list");
            result.addAll(JacksonUtils.parseArray(JacksonUtils.toJsonString(value), SyncCameraResp.class));
            if (value.size() < fetchSize) {
                break;
            }
        }
        LOGGER.debug("海康 获取监控点资源成功 total {}", result.size());

        Map<String, EncodeDeviceDetailResp> encodeDeviceCache = new HashMap<>();
        return result.stream().map(d -> {
            d.setEncodeDeviceDetailResp(encodeDeviceCache.computeIfAbsent(d.getEncodeDevIndexCode(), this::encodeDeviceDetail));
            return d;
        }).collect(Collectors.toList());
    }

    /**
     * 获取默认监控点直播流url
     *
     * @param codeList 设备编码集合
     * @return 视频流url集合
     */
    public List<String> previewDefaultUrl(List<String> codeList) {
        return previewUrl(codeList, 0, "hls", 1);
    }

    /**
     * 获取监控点直播流url
     * 涉及的api包括:
     * 获取监控点预览取流URL path:/api/video/v1/cameras/previewURLs
     *
     * @param codeList   设备编码集合
     * @param streamType 码流类型 0主码流 1子码流 2第三码流
     * @param protocol   取流协议 “rtsp”:RTSP协议,“rtmp”:RTMP协议,“hls”:HLS协议
     * @param transMode  传输协议 0UDP 1TCP
     * @return 视频流url集合
     */
    public List<String> previewUrl(List<String> codeList, Integer streamType, String protocol, Integer transMode) {
        Map<String, Object> params = new HashMap<>();
        params.put("streamType", streamType);
        params.put("protocol", protocol);
        params.put("transmode", transMode);

        final String path = "/api/video/v1/cameras/previewURLs";

        List<String> urls = new ArrayList<>();
        for (String indexCode : codeList) {
            String url = "";
            params.put("cameraIndexCode", indexCode);
            try {
                String response = requester.post(path, params);
                JsonNode respJson = JacksonUtils.parse(response);
                String code = respJson.get("code").asText();
                if (SUCCESS_CODE.equals(code)) {
                    url = respJson.findValue("data").get("url").asText();
                }
            } catch (Exception e) {
                LOGGER.error("海康 监控点取流异常 indexCode {}", indexCode, e);
            }
            urls.add(url);
        }
        return urls;
    }


    /**
     * 获取回放地址
     * 涉及的api包括:
     * 获取监控点回放取流URL path:/api/video/v1/cameras/playbackURLs
     *
     * @param cameraIndexCode 设备唯一标识
     * @param protocol        取流协议 “rtsp”:RTSP协议,“rtmp”:RTMP协议,“hls”:HLS协议
     * @param transMode       传输协议 0UDP 1TCP
     * @param startTime       开始时间
     * @param endTime         结束时间
     * @return 视频流url
     */
    public String playbackUrls(String cameraIndexCode, String protocol, Integer transMode,
                               Date startTime, Date endTime) {

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");


        Map<String, Object> params = new HashMap<>();
        params.put("cameraIndexCode", cameraIndexCode);
        params.put("recordLocation", "1");
        params.put("protocol", protocol);
        params.put("transmode", transMode);
        params.put("beginTime", sdf.format(startTime));
        params.put("endTime", sdf.format(endTime));
        params.put("expand", "streamform=rtp");

        final String path = "/api/video/v2/cameras/playbackURLs";
        String response = requester.post(path, params);
        JsonNode respJson = JacksonUtils.parse(response);
        String code = respJson.get("code").asText();
        if (SUCCESS_CODE.equals(code)) {
            JsonNode data = respJson.get("data");
            if (data != null) {
                return data.get("url").asText();

            }
        }
        return null;
    }


}
